Object

Section: ET++ class description (n)
Updated: automatically Fri Mar 1 10:54:57 1991
Index Return to Main Contents
 

NAME

Object.short - the root of the ET++ class inheritance tree  

DESCRIPTION

Object is the base of virtually all ET++ classes. All classes derived from Object are called regular, in contrast to the so-called built-ins like Point, Rectangle, Token, and classes like Iterator that have derivations, but are nonetheless not regular for special reasons. Instances of regular classes are analogously called regular objects.


Object defines the fundamental protocols for the following concepts: Class Descriptors, Dynamic Type-Checking, Dynamic Creation, Object Copying, Object Input/Output, Change Propagation, and Object Comparison. Furthermore, there are protocols covering Error Handling, Flag Handling, and a binding to the ET++ Programming Environment. Object also defines a virtual destructor which is extremely important.
Furthermore, every regular object is registered in the global object table within Object's constructor, and unregistered within Object's destructor. Use of the object table is optional (see the src/makefile), but it is required by the Inspector.


Class Descriptors and Dynamic Type-Checks


Every regular class has an associated class descriptor providing information about the class at run-time. The class descriptor itself is an regular object, namely an instance of the class Class. The most important information in a class descriptor are the name of the class it belongs to, and a pointer to the class descriptor of the base class. Additionally, the class descriptor holds an so-called prototype object. Prototype objects are particularly important for an portable implementation of the New operation (see below).
The information contained in the class descriptor is what the term meta info refers to. Since other operations of Object's protocols require the presence of the class descriptor, it is absolutely essential. Examples are DeepClone (copying), ReadFrom and PrintOn (Object I/O).
Every regular object can be asked for its class descriptor by IsA. IsA and also IsKindOf allow for dynamic type-checks. Furthermore, there is the Guard construct that provides type-safe casts. A class descriptor can be also obtained either by the Meta construct or from the class manager, a single global object.
In order to support the ET++ Programming Environment, the class descriptor also contains references into the source code and informations about name and static type of the instance variables, provided they have been listed in the meta implementation.
The class descriptor for a class is set up by MetaDef and MetaImpl. MetaDef is part of the class's declaration, and MetaImpl of the class's implementation. The following example shows how it is typically done:

// file: A.h

#include "Object.h"

class A : public Object {
    Object *anObject;
    int aNumber;
public:
    MetaDef(A);
    A();
    ...
};

// file: A.C

MetaImpl(A, (TP(anObject), T(aNumber), 0));   



Dynamic Creation and Object Copying


Beside its information keeping task, the class descriptor is responsible for the dynamic creation of new working objects. Dynamic creation is needed since the C++ new operator requires that the class name is supplied, thus, it is not possible to create an object without statically specifying its class name. The New operation allows to directly ask an existing object for a new working object of the same class.
Object also generically implements two methods for copying objects. method Clone returns a shallow copy, method DeepClone creates a deep copy of the receiver.
A shallow copy is an object that is initialized exactly the same way as the copy constructor of its class would. Clone is part of Object's interface for the same reason as New. The clone generally shares its part objects with the source object (the receiver). Which referenced objects are parts, and which objects are to be duplicated although they are parts of their containing object, depends on the precise semantics of the class.
Conceptually, the method DeepClone returns a deep copy of the receiver by recursively applying a DeepClone to all part objects of the receiver. The generic implementation of DeepClone uses Object I/O (with streams operating on a buffer in memory).
The FreeAll operation is somewhat related to Object Copying. It allows to recursively delete the part objects. As a rule-of-thumb, FreeAll is applied to all part objects (and auxilliary objects, off course), but not to acquainted objects.


Object Input/Output


The Object I/O facility writes and reads arbitrarily complex object graphs in a textual, machine-independent format to a stream (by operator<< and @Object::PrintOn), or from a stream (by operator>>and @Object::ReadFrom), respectively. ET++ Object I/O takes an half-automated object I/O approach.

The stream may operate on a file of the operating system, on a buffer in memory, or whatever might be hidden by a stream. Object I/O properly handles circular references. In other words, an object graph is linearized when output, and correctly rebuilt when input.
Identification of objects due to linearization during input and output is done by operator<<, and operator>>, respectively. The identity of objects bases on pointer identity, thus a pointer book-keeping is maintained during object I/O operations. When during output an object is encountered that has been already output, then an index identifying that object is output, no more the object itself. If such an index has been read during input, the pointer variable is assigned the pointer of the already existing object. This is done by operator>>. If the object to be input has not yet been constructed, operator>> allocates an object of the appropriate class, and the object is initialized by ReadFrom. In the current version, the pointer book-keeping is maintained by the class manager. In future versions, this is accomplished by the streams themselves.
The primary purpose of PrintOn and ReadFrom is to apply operator<<, or operator>> respectively, to their instance variables. Both methods are hooks for their corresponding shift operators. Furthermore, ReadFrom has constructor-like qualities, because the instance variables are initialized such that a working object results. Notice that the operator>> allocates memory, so it has a similar role like the operator new.
The client has to properly override PrintOn and ReadFrom only to get Object I/O working (assuming that the class descriptor is present). If the client introduces new built-ins, he has to provide appropriate overloadings of operator<< and operator>>. See the built-in class Point, for instance.


Object I/O additionally supports Dynamic Linking of classes; when an class is encountered during input whose code is currently not present in the image of the application's process, ET++ tries to find the object code for that class and links it to the running application (see technote 'Dynamic Linking'; there is no further coverage in Object's reference documentation on this topic).


Object Comparison



If objects of a certain class are to be put into collections, then the class should override the comparison methods. Collection classes call the method IsEqual for searching and the method Compare for sorting. The class Set uses the method Hash for fast access to the objects.
Examples for these methods can be found in the class ByteArray, the class ObjFloat or the class VObject.


Change Propagation


The Change Propagation mechanism supports the distribution (or "propagation") of conceptual events with a minimal coupling between the object where the state transition happened, and the objects that shall react on this event. Change Propagation is most often used to establish a binding between models and views in the sense of MVC.
Objects interested in changes of another object register themselves as observers of that object with the method AddObserver. An observer is unregistered by method RemoveObserver. The observers of an object can be viewed as an identity set. The observed object announces changes in its state through the method Send, and the observers are notified by invocation of method DoObserve. The death of the observed object is also such a conceptual event, and observers are notified in this special case, too.
Change Messages are not explicitly modelled as objects. A change message consists of two codes describing first the role of the changed object (so-called id's), and second the changed aspect (so-called part codes). A value whose type and semantics depend on the id and the part code may further describe the change. The sender of the message is available to the observers so they can inquire of the observed object.

   Change Propagation includes the concept of Delayed Changes. For every object, there is an so-called delayed changes message counter. For each DelayChanges call, the counter is incremented by one. The change messages are eventually forwarded to the observers, if the delayed changes counter is zero or gets zero after the according number of calls to FlushChanges. The counter is initially zero, and cannot drop below zero. If an observed object is deleted and there are still pending change messages, they are simply discarded. It is implementation-dependent what happens with delayed change messages sent at a time at which the sender has no observers.


Examples:
The class Text uses change propagation, so an observing class TextView can update the display when the text changes. The text classes also use the delayed change mechanism.
The Inspector of the ET++ Programming Environment also uses change propagation by registering itself as an observer of the currently inspected object.


Flag Handling


Object manages a set of flags which are stored efficiently in the instvar flags. Some of the flags are used internally. New flags may be defined in subclasses.
Flags for a class are defined by an enumeration type and by means of the macro BIT as in the following example:

enum CommandFlags {
    eCmdCanUndo        = BIT(eObjLast+1),
    eCmdCausesChange   = BIT(eObjLast+2),
    ...
    eCmdNoReplFeedback = BIT(eObjLast+8),
    eCmdLast           = eObjLast + 8
};


The enumeration values must always be defined relative to the last flag of a super class (in the above example Object). Thus, the value of the first flag is determined this way:
        - find the nearest super class which added some flags.
        - take the last enumeration value of that class.
        - increment it by one.

In the above example the first flag for subclasses of the class Command would be BIT(eCmdLast+1).
Object provides several methods to test and manipulate flags (method TestFlag, method SetFlag, method ResetFlag and method InvertFlag). Several flags can be processed simultaneously by "or'ing" together the enumeration values, f.i. SetFlag(eCmdCanUndo|eCmdCausesChange);.


Error Handling


Object provides a general error handling facility which uniformly handles program and system errors.
There are 4 error handling methods (method Warning, method Error, method SysError and method Fatal) which represent 4 different error levels indicating the severeness of the error. These methods take the following arguments: the location (the name of the method where the error occurred) and a format string in the style of printf with optional arguments.
The default error handler of ET++ prints the error message on the standard error output. See technote 'Error Handling'.


Connection to the ET++ Programming Environment (ET++PE)


The ET++PE depends on the metaclass information (see "Metaclasses" above) to be able to display static and dynamic relationships between classes and objects and to find the location of the source files of a class. Besides that, the Inspector can display instance variables only if they have been included in the macro MetaImpl.
The ET++PE can additionally be supported by overriding the method Parts and the method InspectorId. The method Parts allows to add important referenced objects to a list which is used by the Object Structure Browser to show dynamic relationships between objects. The method InspectorId should return an identification string which is displayed by the Inspector and other views of the ET++PE. For example, the method Document::InspectorId returns the document name.
The Inspector and the Source Code Browser of the ET++PE can also be started directly through method Inspect and method EditSource.


classes are always derived from Object.
class Object is never reused directly.
class Object is abstract.
class Object contains 54 methods.

owner of class:
nobody.
baseclasses:
Root
subclasses:
AbstractViewPolicy, Assoc, BagItem, BitSet, ByteArray, ChangeMessage, Class, ClassManager, Collection, Command, DeletedObject, EvtHandler, Ink, Mark, ObjFloat, ObjInt, ObjLink, PathLookup, Picture, ProgEnv, RegularExp, Style, SysEvtHandler, Text, TextFormatter
friend classes:
Class
friend functions:
_Type, operator<<, operator>>
flags:
ObjFlags

 

CLASS VARIABLES

isa (public Class *)
refers to the class descriptor of the class.
For all regular classes, isa is automatically created and initialized by the macro MetaDef and the macro MetaImpl.
See technote Metaclasses. Use the method IsA to access the metaclass of an object.
Known Problems: isa must not be accessed despite its public access. It should be protected.

 

INSTANCE VARIABLES

flags (private u_int)
stores the flags of an object as a bitset.
The maximum number of available flags depends on the size of an u_int. On most machines u_int occupies 32 bits. In this case up to 22 user-defined flags may be defined in subclasses because 10 flags are always reserved for internal use. Flags can be tested with method TestFlag and modified with method SetFlag, method ResetFlag or method InvertFlag.

 

INSTANCE METHOD LIST

change propagation
AddObserver
Changed
CleanupObservers
DelayChanges
DestroyObserverColl
DoObserve
FlushChanges
GetObserverIter
GetObservers
MakeObserverColl
RemoveObserver
Send
SetObserverColl

client
DisplayOn

comparison
Compare
Hash
IsEqual

constructor
Object

conversion
AsString

copying
Clone
DeepClone

creation
InitNew
New

destruction
FreeAll

destructor
~Object

error handling
DoError
Error
Fatal
SysError
Warning

fire walls
AbstractMethod
MayNotUse

flag handling
ClearVisited
InvertFlag
IsDeleted
IsObserved
MarkAsDeleted
ResetFlag
SetFlag
SetVisited
TestFlag

meta info
ClassName

metaclass
GetAddrOf
IsA
Members
guard

object i/o
PrintOn
PrintOnWhenObserved
ReadFrom

progenv support
EditSource
Inspect
InspectorId
Parts

 

CATEGORIES

Foundation

 

FILES

declaration:
Object.h

 

HISTORY

joe - May 28 1991 - created
chris - May 29 1991 - reviewed
gil - May 31 1991 - reviewed
joe, chris - Jun 3 - minor changes
T. Kofler/SBG - Sep 3 1991. - Totally reworked.


 

Index

NAME
DESCRIPTION
CLASS VARIABLES
INSTANCE VARIABLES
INSTANCE METHOD LIST
CATEGORIES
FILES
HISTORY

This document was created by man2html, using the manual pages.
Time: 00:40:26 GMT, March 30, 2022